package com.ea.eadp.nexus.test.common.ApiClients;

/**
 * Created by ChuanYe on 7/24/2014.
 */
import com.ea.eadp.nexus.test.common.HttpsClient;
import com.ea.eadp.nexus.test.common.SystemProperties;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpHost;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.impl.conn.SchemeRegistryFactory;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
 * Created by ChuanYe on 7/23/2014.
 */
public class NexusHttpClients {
    private static int socketTimeout = Integer.parseInt(SystemProperties.instance().getProperty(SystemProperties.socketTimeout));
    private static int connectionTimeout = Integer.parseInt(SystemProperties.instance().getProperty(SystemProperties.connectionTimeout));
    private static int connectionTimeToLive = Integer.parseInt(SystemProperties.instance().getProperty(SystemProperties.connectionTimeToLive));
    private static int maxTotal = Integer.parseInt(SystemProperties.instance().getProperty(SystemProperties.httpMaxTotal));
    private static int maxPerRoute = Integer.parseInt(SystemProperties.instance().getProperty(SystemProperties.httpMaxPerRoute));

    private static String facebookProxyHost = SystemProperties.instance().getProperty(SystemProperties.FacebookProxyHost,"");
    private static String facebookProxyPort = SystemProperties.instance().getProperty(SystemProperties.FacebookProxyPort,"");

    private static PoolingClientConnectionManager connectionManager;

    private static DefaultHttpClient connectClient;
    private static DefaultHttpClient gatewayClient;
    private static DefaultHttpClient facebookClient;
    private static DefaultHttpClient nucleusClient;

    private static Map<String, HttpsClient> httpsClients;

    private static synchronized void init() {
        if(connectionManager == null) {
            connectionManager = new PoolingClientConnectionManager(SchemeRegistryFactory.createDefault(), connectionTimeToLive, TimeUnit.MILLISECONDS);
            connectionManager.setDefaultMaxPerRoute(maxPerRoute);
            connectionManager.setMaxTotal(maxTotal);
            //execute timed task to release Idle connection
            /*  ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, new DaemonThreadFactory(
                    "httpClient-con-monitor"));
            scheduler.scheduleAtFixedRate(new IdleConnectionMonitor(connectionManager),10000, connectionTimeToLive, TimeUnit.MILLISECONDS);
            */
        }
    }

    public static synchronized DefaultHttpClient getConnectClient() {
        init();
        if(connectClient == null) {
            connectClient = createHttpClient();
        }
        //remove the sid in cookie to avoid autologin for mobilefacebook, mobileupid etc.
        connectClient.getCookieStore().clear();
        return connectClient;
    }

    public static synchronized DefaultHttpClient getGatewayClient() {
        init();
        if(gatewayClient == null) {
            gatewayClient = createHttpClient();
        }
        return gatewayClient;
    }

    public static synchronized DefaultHttpClient getFacebookClient() {
        init();
        if(facebookClient == null) {
            facebookClient = createHttpClient();
            if (!StringUtils.isBlank(facebookProxyHost)){
                HttpHost proxy = new HttpHost(facebookProxyHost, Integer.valueOf(facebookProxyPort));
                HttpParams params = facebookClient.getParams();
                params.setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
            }
        }
        return facebookClient;
    }

    public static synchronized DefaultHttpClient getNucleusClient() {
        init();
        if(nucleusClient == null) {
            nucleusClient = createHttpClient();
        }
        return nucleusClient;
    }

    public static synchronized HttpsClient getHttpsClient(String keyStoreName) throws Exception {
        init();
        if(httpsClients == null) {
           httpsClients = new HashMap<String, HttpsClient>();
        }
        if(httpsClients.containsKey(keyStoreName) == false) {
            httpsClients.put(keyStoreName, createHttpsClient(keyStoreName));
        }
        return httpsClients.get(keyStoreName);
    }

    private static DefaultHttpClient createHttpClient() {
        DefaultHttpClient client = new DefaultHttpClient(connectionManager);
        HttpParams params = client.getParams();
        HttpConnectionParams.setSoTimeout(params, socketTimeout);
        HttpConnectionParams.setConnectionTimeout(params, connectionTimeout);
        try {
            client=SslUtils.trustAllHttpsCertificates(client);
        } catch (Exception e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
        return client;
    }

    private static HttpsClient createHttpsClient(String keyStoreName) throws Exception{
        HttpsClient client = new HttpsClient(keyStoreName);
        HttpParams params = client.getParams();
        HttpConnectionParams.setSoTimeout(params, socketTimeout);
        HttpConnectionParams.setConnectionTimeout(params, connectionTimeout);
        return client;
    }
    private static final class IdleConnectionMonitor implements Runnable {
        PoolingClientConnectionManager connectionManager;
        protected final Log log = LogFactory.getLog(getClass());

        public IdleConnectionMonitor(PoolingClientConnectionManager connectionManager) {
            this.connectionManager = connectionManager;
        }

        @Override
        public void run() {
            if (log.isInfoEnabled()) {
                log.debug("release start connect count:=" + connectionManager.getTotalStats().toString());
            }
            // Close expired connections
            connectionManager.closeExpiredConnections();
            // Optionally, close connections
            // that have been idle longer than readTimeout*2 MILLISECONDS
            connectionManager.closeIdleConnections(socketTimeout * 2, TimeUnit.MILLISECONDS);

            if (log.isInfoEnabled()) {
                log.debug("release end connect count:=" + connectionManager.getTotalStats().toString());
            }

        }
    }

}
